home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / mint / filesy~1 / mfs609s.zoo / fsck / fsck.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-11-25  |  29.9 KB  |  1,458 lines

  1. /* Filesystem checker : Contains most of the elements of BSD fsck(8) that
  2.  * make sense under minix filesystems.
  3.  * Copyright 1992 S.N. Henson, all rights reserved.
  4.  * Version 0.0 pre-alpha [i.e. likely to be buggy].
  5.  */
  6.  
  7. /* Patchlevel 6 */
  8.  
  9. #include <sys/types.h>
  10. #include <unistd.h>
  11. #include <alloc.h>
  12. #include <time.h>
  13. #include <stdio.h>
  14. #include <macros.h>        /* For min(x,y) */
  15. #include <string.h>
  16. #include <stdlib.h>
  17. #include <time.h>
  18.  
  19. #include "fs.h"
  20. #include "fsck.h"
  21. #include "global.h"
  22. #include "proto.h"
  23. #include "stproto.h"
  24.  
  25. void do_fsck()
  26. {
  27.     int pass;
  28.     long i;
  29.  
  30.     read_tables();
  31.  
  32.     /* Filesystem dependent check */
  33.  
  34.     i = 2+Super->s_zmap_blks+Super->s_imap_blks
  35.                         +(Super->s_ninodes+IPB-1)/IPB;
  36.  
  37.     if( Super->s_firstdatazn < i ) sfatal("First Data Zone too small");
  38.  
  39.     /* Maybe using new protection ? */
  40.     if( Super->s_firstdatazn > i ) 
  41.     {
  42.         unsigned char *tblock;
  43.         long secsize;
  44.         tblock = malloc(BLOCKSIZE);
  45.         if(!tblock) fatal("No memory for boot sector buffer");
  46.         read_zone(0,tblock);
  47.         secsize = tblock[0xb]+(tblock[0xc]<<8);
  48.         if( ((secsize & 1023 ) == 0))
  49.         {
  50.             secsize/=1024;
  51.             i+= 2 * secsize - 1;
  52.             i/=secsize;
  53.             i*=secsize;
  54.         }
  55.         free(tblock);
  56.     }
  57.  
  58.     if( Super->s_firstdatazn != i ) fprintf(stderr,"Warning: First data" 
  59.         " zone block %d, expected %ld\n",Super->s_firstdatazn,i);
  60.  
  61.     /* Allocate status arrays */
  62.  
  63.     ibitmap=calloc(BLOCKSIZE*(Super->s_zmap_blks*2 + Super->s_imap_blks) +
  64.                     sizeof(inode_stat)*Super->s_ninodes,1);
  65.  
  66.     if(!ibitmap)fatal("No memory for Zone bitmaps");
  67.  
  68.     zbitmap=(unsigned *)( ( (long)ibitmap )+ BLOCKSIZE*Super->s_imap_blks);
  69.     szbitmap=(unsigned *)( ( (long)zbitmap ) + BLOCKSIZE*Super->s_zmap_blks);
  70.     inode_status=(inode_stat *)(szbitmap +(szbitmap-zbitmap));
  71.  
  72.     setbit(0,szbitmap);
  73.  
  74.     /* Flags for root inode */
  75.     inode_status->flag |= I_FOUND;
  76.     inode_status->parent= ROOT_INODE;
  77.  
  78.     /* Read in all bitmaps */
  79.     read_blocks(2,Super->s_imap_blks+Super->s_zmap_blks,ibitmap);
  80.     ioff=2+Super->s_imap_blks+Super->s_zmap_blks;
  81.  
  82.     check_root();
  83.  
  84.     printf("Pass 1 Checking All Inodes\n");
  85.  
  86.     ist=inode_status;
  87.     next_init();
  88.  
  89.     for(cino=ROOT_INODE;cino<=maxino;cino++,ist++)
  90.     {
  91.         next_inode();
  92.         if(badroot && (cino==ROOT_INODE) ) continue;
  93.         ist->links=rip->i_nlinks;
  94.         switch(rip->i_mode & I_TYPE)
  95.         {
  96.             case I_NOT_ALLOC:
  97.             ist->flag|=I_FREE;
  98.             if(rip->i_nlinks)
  99.             {
  100.                 printf("Non zero link count for Free inode %ld\n",cino);
  101.                 if(ask("Alter?","Altered"))
  102.                 {
  103.                     rip->i_nlinks=0;
  104.                     ist->links=0;
  105.                     cdirty=1;
  106.                 }
  107.             }
  108.             break;
  109.  
  110.             case I_CHAR_SPECIAL:
  111.             nchr++;
  112.             break;
  113.  
  114.             case I_BLOCK_SPECIAL:
  115.             nblk++;
  116.             break;
  117.  
  118.             case I_NAMED_PIPE:
  119.             nfifo++;
  120.             break;
  121.  
  122.             case I_REGULAR:
  123.             nreg++;
  124.             traverse_zones(pass1);
  125.             break;
  126.  
  127.             case I_DIRECTORY:
  128.             ndir++;
  129.             if(rip->i_size & (DSIZE*incr-1))
  130.             {
  131.                 inerr("Partial Entry");
  132.                 if(ask("Truncate?","Truncated"))
  133.                 {
  134.                     rip->i_size &= ~(DSIZE*incr-1);
  135.                     cdirty=1;
  136.                     trunc=2;
  137.                 }
  138.             }
  139.             traverse_zones(pass1);
  140.             trunc=0;
  141.             ist->flag|=I_DIR;
  142.             break;
  143.  
  144.             case I_SYMLINK:
  145.             nsym++;
  146.             traverse_zones(pass1);
  147.             break;
  148.  
  149.             default:
  150.             printf("Unknown Mode 0%o Inode %ld\n",rip->i_mode,cino);
  151.             if(ask("Clear?","Cleared"))
  152.             {
  153.                 *rip=zinode;
  154.                 cdirty=1;
  155.                 ist->links=0;
  156.             }
  157.         }
  158.     }
  159.  
  160.     if(fzlist)
  161.     {
  162.         if(preen) fatal("Duplicate zones found when preening");
  163.         printf("Pass 1a finding duplicate zones\n");
  164.         next_init();
  165.         for(cino=ROOT_INODE;cino<=maxino;cino++)
  166.         {
  167.             next_inode();
  168.             if(badroot && (cino==ROOT_INODE) ) continue; 
  169.             switch(rip->i_mode & I_TYPE)
  170.             {
  171.                 case I_SYMLINK:
  172.                 case I_REGULAR:
  173.                 case I_DIRECTORY:
  174.                 traverse_zones(pass1a);
  175.  
  176.                 default:
  177.                 break;
  178.             }
  179.         }
  180.     }
  181.  
  182.     next_init();
  183.  
  184.     if(badroot) fix_root();
  185.  
  186.     for(pass=0;pass<4;pass++)
  187.     {
  188.         char first=0;
  189.         switch(pass)
  190.         {
  191.             case 0:
  192.             printf("Pass 2 Reading Directories\n");
  193.             break;
  194.             
  195.             case 1:
  196.             printf("Pass 3 Checking Connectivity\n");
  197.             break;
  198.  
  199.             case 2:
  200.             case 3:
  201.             first=0;
  202.             break;
  203.         }
  204.         read_inode_init();
  205.         ist=inode_status;
  206.         for(cino=ROOT_INODE;cino<=maxino;cino++,ist++)
  207.         {
  208.             if(!(ist->flag & I_DIR)) continue;
  209.             if( (pass==2) && !(ist->flag & I_LINK) ) continue;
  210.             if( (pass==3) && ( !(ist->flag & (I_FDD|I_FIXDD)) 
  211.                     || !(ist->flag & I_DD) ) ) continue;
  212.             read_inode();
  213.             switch(pass)
  214.             {
  215.                 case 0:
  216.                 check_dots();
  217.                 break;
  218.  
  219.                 case 1:
  220.                 traverse_dir(pass2);
  221.                 break;
  222.  
  223.                 case 2:
  224.                 if(!first)
  225.                 {
  226.                     printf("Pass 3a Fixing Directories\n");
  227.                     first=1;
  228.                 }
  229.                 traverse_dir(pass2a);
  230.                 break;
  231.  
  232.                 case 3:
  233.                 if(!first)
  234.                 {
  235.                     printf("Pass 3b Fixing Dots\n");
  236.                     first=1;
  237.                 }
  238.                 fix_dots();
  239.                 break;
  240.             }
  241.         }
  242.     }
  243.     ist=inode_status;
  244.  
  245.     if(inolist)
  246.     {
  247.         ilist *p;
  248.         for(p=inolist;p;p=p->next) show_name(p);
  249.     }
  250.  
  251.     for(cino=ROOT_INODE;cino<=maxino;cino++,ist++)
  252.     {
  253.  
  254.         if( !(ist->flag & I_FOUND) && !(ist->flag & I_FREE) )
  255.         {
  256.             inerr("Orphaned Inode");
  257.             if(ask("Reconnect?","Reconnected"))
  258.             {
  259.                 dir_struct tdir[DPB/2];
  260.                 unsigned tino;
  261.                 if(lfinode || mklost() )
  262.                 {
  263.                 read_inode();
  264.                 cdirty=1;
  265.                 tino=cino;
  266.                 rip->i_nlinks++;
  267.  
  268.                 /* Fix link count as well */
  269.                 rip->i_nlinks-=ist->links;
  270.                 ist->links=0;
  271.  
  272.                 /* Update '..' */
  273.                 if(ist->flag & I_DD)
  274.                 {
  275.                     dir_struct dir[DPB];
  276.                     read_zone(rip->i_zone[0],dir);
  277.                     dir[incr].d_inum=lfinode;
  278.                     write_zone(rip->i_zone[0],dir);
  279.  
  280.                     if(chk_irange(ist->parent))
  281.                     {    
  282.                     inode_status[ist->parent-1].links++;
  283.                     cino=ist->parent;
  284.                     read_inode();
  285.                     cdirty=1;
  286.                     rip->i_nlinks--;
  287.                     }
  288.  
  289.                 }
  290.  
  291.                 cino=lfinode;
  292.                 sprintf(tdir[0].d_name,"%d",tino);
  293.                 tdir[0].d_inum=tino;
  294.  
  295.                 read_inode();
  296.                 if(ist->flag & I_DD) rip->i_nlinks++;
  297.                 cdirty=1;
  298.                 add_dirent(tdir);
  299.                 cino=tino;
  300.                 }
  301.             else printf("Cannot Reconnect\n");
  302.             }    
  303.         }
  304.  
  305.         if(ist->links)
  306.         {
  307.             printf("Inode %ld Bad Link Count\n",cino);
  308.             if(ask("Alter?","Altered"))
  309.             {
  310.                 read_inode();
  311.                 rip->i_nlinks-=ist->links;
  312.                 ist->links=0;
  313.                 cdirty=1;
  314.             }
  315.         }
  316.  
  317.     }
  318.  
  319.     read_inode_init();
  320.  
  321.     printf("Checking Zone Bitmap\n");
  322.     for(i=1;i<=maxzone-minzone+1;i++)
  323.     {
  324.         if(!isset(i,szbitmap))
  325.         {
  326.             zfree++;
  327.             if(isset(i,zbitmap)) berr++;
  328.         }
  329.         else if(!isset(i,zbitmap)) berr++;
  330.     }
  331.  
  332.     if(berr)
  333.     {
  334.         printf("Zone Bitmap : %ld Errors\n",berr);
  335.         if(ask("Install A New Map?","Fixed"))
  336.         {
  337.             for(i=1;i<=maxzone-minzone+1;i++)
  338.             {
  339.                 if(isset(i,szbitmap)) setbit(i,zbitmap);
  340.                 else clrbit(i,zbitmap);
  341.             }
  342.             write_blocks(2+Super->s_imap_blks,Super->s_zmap_blks,zbitmap);
  343.         }
  344.     }
  345.     else printf("Zone Bitmap OK\n");
  346.  
  347.     berr=0;
  348.     ist=inode_status;
  349.     printf("Checking Inode Bitmap\n");
  350.  
  351.     for(i=ROOT_INODE;i<=maxino;i++,ist++)
  352.     {
  353.         if( ist->flag & I_FREE)
  354.         {
  355.             ifree++;
  356.             if(isset(i,ibitmap)) berr++;
  357.         }
  358.         else if(!isset(i,ibitmap)) berr++;
  359.     }
  360.  
  361.     if(berr)
  362.     {
  363.         printf("Inode Bitmap : %ld Errors\n",berr);
  364.         if(ask("Install A New Map?","Fixed"))
  365.         {
  366.             ist=inode_status;
  367.             for(i=ROOT_INODE;i<=maxino;i++,ist++)
  368.             {
  369.                 if(ist->flag & I_FREE) clrbit(i,ibitmap);
  370.                 else setbit(i,ibitmap);
  371.             }
  372.             write_blocks(2,Super->s_imap_blks,ibitmap);
  373.         }
  374.     }
  375.     else printf("Inode Bitmap OK\n");
  376.  
  377.     read_inode_init();
  378.  
  379. }
  380.  
  381. /* traverse_zones passes pointers of the zone numbers of inode 'rip' to the 
  382.  * function argument, if the value returned is non-zero then number was altered.
  383.  * Also pass a 'level' parameter, this is zero for zone numbers, 1 for 
  384.  * indirection blocks and 2 for double indirection blocks.
  385.  */
  386.  
  387. static void traverse_zones(func)
  388. int (*func)(zone_nr *zone,unsigned level);
  389. {
  390.     zone_nr i,j;
  391.     zone_nr tmp1[NINDIR],tmp2[NINDIR];
  392.  
  393.     zonecount=(rip->i_size+BLOCKSIZE-1)/BLOCKSIZE;
  394.     indcount=NO_IND(zonecount);
  395.     dindcount=NO_DBL(zonecount);
  396.  
  397.     if(trunc!=2) trunc=0; /* 2 means silently truncate (directory) */
  398.     done_trunc=0;
  399.  
  400.     for(i=0;i<NR_ZONE;i++)
  401.         if( (*func)(&rip->i_zone[i],(i<NDIR) ? 0 : (i-NDIR+1) ) )
  402.                                        cdirty=1;
  403.  
  404.     if( chk_range(rip->i_zone[NDIR]) )
  405.     {
  406.         int zdirty=0;
  407.         read_zone(rip->i_zone[NDIR],tmp1);
  408.  
  409.         for(i=0;i<NINDIR;i++) if( (*func)(&tmp1[i],0) ) zdirty=1;
  410.         if(zdirty) write_zone(rip->i_zone[NDIR],tmp1);
  411.     }
  412.     else zonecount-=NINDIR;
  413.  
  414.     if( chk_range(rip->i_zone[NDIR+1]) )
  415.     {
  416.         int zdirty=0;
  417.         read_zone(rip->i_zone[NDIR+1],tmp1);
  418.         for(i=0;i<NINDIR;i++)
  419.         {
  420.             if( (*func)(&tmp1[i],1) )
  421.             {
  422.                 zdirty=1;
  423.                 continue;
  424.             }
  425.             if( chk_range(tmp1[i]) )
  426.             {
  427.                 int zdirty2=0;
  428.                 read_zone(tmp1[i],tmp2);
  429.                 for(j=0;j<NINDIR;j++)
  430.                     if( (*func)(&tmp2[j],0) ) zdirty2=1;
  431.                 if(zdirty2) write_zone(tmp1[i],tmp2);
  432.             }
  433.             else zonecount-=NINDIR;
  434.  
  435.             if(zdirty) write_zone(rip->i_zone[NDIR+1],tmp1);
  436.         }
  437.     }
  438. }
  439.  
  440. /* Pass 1 zone traversal , check zone range and note in bitmap, do truncation
  441.  * if too many zones.
  442.  */
  443.  
  444. static int pass1(zone,level)
  445. zone_nr *zone;
  446. unsigned level;
  447. {
  448.  
  449.     if(!done_trunc || trunc)
  450.     {
  451.         switch(level)
  452.         {
  453.             case 0:
  454.  
  455.             if(zonecount==0)
  456.             {
  457.                 if(*zone && ( trunc || do_trunc() ) )
  458.                 {
  459.                     *zone=0;
  460.                     return 1;
  461.                 }
  462.             }
  463.             else zonecount--;
  464.             break;
  465.  
  466.             case 1:
  467.             if(indcount==0)
  468.             {
  469.                 if(*zone && ( trunc || do_trunc() ) )
  470.                 {
  471.                     *zone=0;
  472.                     return 1;
  473.                 }
  474.             }
  475.             else indcount--;
  476.             break;
  477.  
  478.             case 2:
  479.             if(dindcount==0)
  480.             {
  481.                 if(*zone && (trunc || do_trunc() ) )
  482.                 {
  483.                     *zone=0;
  484.                     return 1;
  485.                 }
  486.             }
  487.             else dindcount--;
  488.             break;
  489.         }
  490.     }
  491.  
  492.     if(!*zone) return 0; /* zero is legitimate */
  493.     if( (*zone < minzone) || (*zone > maxzone) )
  494.     {
  495.         printf("Zone number out of range in inode %ld\n",cino);
  496.         if(ask("Remove?","Removed"))
  497.         {
  498.             *zone=0;
  499.             return 1;
  500.         }
  501.     }
  502.  
  503.     if(mark_zone(*zone)) add_dup(*zone);
  504.     return 0;
  505. }
  506.  
  507. /* Comment : at the end of pass 1 we have a (possibly empty) list of duplicate
  508.  * zones. The crucial point is that they are in the order of finding by 
  509.  * traverse_zones, except the first element is missing, this is tackled by
  510.  * pass1a.
  511.  */
  512.  
  513. /* Pass 1a zone traversal , find first duplicate zones and fix */
  514.  
  515. static int pass1a(zone,level)
  516. zone_nr *zone;
  517. unsigned level;
  518. {
  519.     if(!chk_range(*zone)) return 0;
  520.     if(is_dup(*zone))
  521.     {
  522.         /* Found first member of duplicate zones, prepend
  523.          * to list.
  524.          */
  525.  
  526.         zlist *new;
  527.         new=malloc(sizeof(zlist));
  528.         if(!new) fatal("No memory for duplist\n");
  529.         new->next=fzlist;
  530.         new->mod=rip->i_mtime;
  531.         new->inum=cino;
  532.         new->zone=*zone;
  533.         new->flag=0;
  534.         fzlist=new;
  535.         do_dup(*zone);
  536.     }
  537.     if(is_rem(*zone))
  538.     {
  539.         printf("Removing Zone %ld Inode %ld\n",(long)*zone,cino);
  540.         *zone=0;
  541.         return 1;
  542.     }
  543.     return 0;
  544. }
  545.  
  546. /* add_dup(zone) adds 'zone' to the duplicate list, this is put at the end
  547.  * so that the duplicate zone reflects the position of finding.
  548.  */
  549.  
  550. static void add_dup(zone)
  551. zone_nr zone;
  552. {
  553.     zlist *tlist;
  554.     tlist=(zlist *)malloc(sizeof(zlist));
  555.     if(!tlist) fatal("No memory for duplicate list");
  556.     tlist->zone=zone;
  557.     tlist->inum=cino;
  558.     tlist->mod=rip->i_mtime;
  559.     tlist->next=NULL;
  560.     tlist->flag=0;
  561.     if(lzlist)
  562.     {
  563.         lzlist->next=tlist;
  564.         lzlist=tlist;
  565.     }
  566.     else
  567.     {
  568.         fzlist=tlist;
  569.         lzlist=tlist;
  570.     }
  571. }
  572.  
  573. /* This determines what happens when duplicate zones are all found, the
  574.  * flag FOUND is set on each zone so that we now know that all the list
  575.  * of duplicates for this zone is complete. The user has the choice to
  576.  * remove each zone. Each removal is noted by the flag REMOVE, so that
  577.  * when the zones are tested by is_rem(), they are removed in order.
  578.  */
  579.  
  580. static void do_dup(zone)
  581. zone_nr zone;
  582. {
  583.     zlist *p;
  584.     printf("Zone %ld is multiply allocated\nInode list:\n",(long)zone);
  585.     for(p=fzlist;p;p=p->next)
  586.     {
  587.         if(p->zone!=zone)continue;
  588.         p->flag|=FOUND;
  589.         printf("Inode %d\n",p->inum);
  590.         printf("Mod time %s\n",ctime(&p->mod));
  591.         if(ask("Remove Zone?","Removed")) p->flag |=REMOVE;
  592.     }
  593. }
  594.  
  595. /* Return non-zero if 'zone' is a duplicate. If the FOUND flag is set for
  596.  * this zone ignore the request, as it means that this duplicate zone list
  597.  * is complete.
  598.  */
  599.  
  600. static int is_dup(zone)
  601. zone_nr zone;
  602. {
  603.     zlist *p;
  604.     for(p=fzlist;p;p=p->next)
  605.         if(p->zone==zone)
  606.         {
  607.             if(p->flag & FOUND) return 0;
  608.             return 1;
  609.         }
  610.     return 0;
  611. }
  612.  
  613. /* Returns non-zero if zone is marked for removing, if it is marked then
  614.  * remove the zone member from the duplicate list. If it isn't then set 
  615.  * the flag IGNORE so that subsequent is_rem()'s pass over it silently.
  616.  * If the zone is removed and no zones remain with this number, free its
  617.  * entry in the zone bitmap.
  618.  */
  619.  
  620. static int is_rem(zone)
  621. zone_nr zone;
  622. {
  623.     zlist *p,*q;
  624.     for(p=fzlist,q=0;p;p=p->next)
  625.     {
  626.         if( (p->zone==zone) && !(p->flag & IGNORE))
  627.         {
  628.             if(p->flag & REMOVE)
  629.             {
  630.                 if(!q) fzlist=p->next;
  631.                 else q->next=p->next;
  632.                 free(p);
  633.                 if(p==lzlist) lzlist=q;
  634.                 /* Last reference ? */
  635.                 for(p=fzlist;p && (p->zone!=zone);p=p->next) ;
  636.                 if(!p) unmark_zone(zone);
  637.                 return 1;
  638.             }
  639.             p->flag |= IGNORE;
  640.             return 0;
  641.         }
  642.         q=p;
  643.     }
  644.     return 0;
  645. }
  646.  
  647. /* check_root() test the root inode, determine directory increment if none
  648.  * specified.
  649.  */
  650.  
  651. static void check_root()
  652. {
  653.     dir_struct dir[DPB];
  654.     int i;
  655.     read_inode_init();
  656.     cino=ROOT_INODE;
  657.     read_inode();
  658.     if((rip->i_mode & I_TYPE)!=I_DIRECTORY)
  659.     {
  660.         fprintf(stderr,"Root Inode Not a Directory\n");
  661.         if(!incr)
  662.         {
  663.             fprintf(stderr,"Enter Increment Manually with '-d' option\n");
  664.             close_device();
  665.             exit(1);
  666.         }
  667.         if(!ask("Reallocate?","Reallocated"))
  668.         {
  669.             close_device();
  670.             exit(1);
  671.         }
  672.         badroot=1;
  673.         return;
  674.     }
  675.  
  676.     if(incr) return;
  677.     if(!chk_range(rip->i_zone[0]))
  678.     {
  679.         fprintf(stderr,"Bad First Zone In Root Inode\n");
  680.         if(!ask("Assume Increment 1?","Assuming increment 1"))
  681.         {
  682.             close_device();
  683.             exit(1);
  684.         }
  685.         incr=1;
  686.         return;    
  687.     }
  688.  
  689.     read_zone(rip->i_zone[0],dir);
  690.  
  691.     if(strcmp(dir->d_name,"."))
  692.     {
  693.         fprintf(stderr,"No or bad '.' in Root Inode.\n");
  694.         fprintf(stderr,"Use the '-d' option to set increment.\n");
  695.         close_device();
  696.         exit(1);
  697.     }
  698.  
  699.     for(i=1;i<DPB;i++) if(!strcmp(dir[i].d_name,"..")) break;
  700.  
  701.     if(NPOW2(i) || (i > 8))
  702.     {
  703.         fprintf(stderr,"Can't Work Out Increment: Use the -d option\n");
  704.         close_device();
  705.         exit(1);
  706.     }
  707.  
  708.     incr=i;
  709.     return;
  710. }
  711.  
  712. /* traverse_dir(), send all the entries of a dir (with the entry number),
  713.  * to the function 'func'. If this returns non-zero then the entry was
  714.  * modified, BUG: Ignores double-indirection block, but anyone with a
  715.  * directory this big must be doing it to try and fool us (it means more
  716.  * than 33000 entries !).
  717.  */
  718.  
  719. static void traverse_dir(func)
  720. int (*func)();
  721. {
  722.     unsigned entry=0;
  723.     long nentries=rip->i_size/(DSIZE*incr),i;
  724.     zone_nr nzones=(nentries+DPB/incr-1)/(DPB/incr);
  725.     dir_struct dir[DPB];
  726.     zone_nr znr;
  727.     for(znr=0;znr < min(NDIR,nzones); znr++)
  728.     {
  729.         if(chk_range(rip->i_zone[znr]))
  730.         {
  731.             int zdirty=0;
  732.             read_zone(rip->i_zone[znr],dir);
  733.             for(i=0;(i<min(DPB/incr,nentries)) && !quit_trav;
  734.                                     i++,entry++)
  735.                 if((*func)(&dir[i*incr],entry)) zdirty=1;
  736.             if(zdirty) write_zone(rip->i_zone[znr],dir);
  737.             if(quit_trav) return;
  738.         }
  739.         else entry +=DPB/incr;
  740.         nentries-=DPB/incr;
  741.         if(nentries<=0) return;
  742.     }
  743.     nzones-=NDIR;
  744.     if(chk_range(rip->i_zone[NDIR]) )
  745.     {
  746.         zone_nr tmp[NINDIR];
  747.         read_zone(rip->i_zone[NDIR],tmp);
  748.         for(znr=0;znr<min(NINDIR,nzones);znr++)
  749.         {
  750.             if(chk_range(tmp[znr]))
  751.             {
  752.                 int zdirty=0;
  753.                 read_zone(tmp[znr],dir);
  754.                 for(i=0;(i<min(DPB/incr,nentries)) && !quit_trav;
  755.                                 i++,entry++)
  756.                     if( (*func)(&dir[i*incr],entry) )zdirty=1;
  757.                 if(zdirty) write_zone(tmp[znr],dir);
  758.                 if(quit_trav) return;
  759.             }
  760.             else entry +=DPB/incr;
  761.             nentries-=DPB/incr;
  762.             if(nentries<=0) return;
  763.         }
  764.     }
  765. }
  766.  
  767. /* Add an entry to a dir, this uses traverse_dir to see if there are any
  768.  * free slots, if not then add a zone.
  769.  */
  770.  
  771. static long lastentry;
  772. static dir_struct *add;
  773. static dir_struct newzone[DPB];
  774.  
  775. static int add_dirent(adir)
  776. dir_struct *adir;
  777. {
  778.     long tsize,zoneadd,addz;
  779.     tsize=rip->i_size;
  780.     /* Expand the dir by one entrylength, reset later if get empty slot */
  781.     rip->i_size+=DSIZE*incr;
  782.     rip->i_size &= ~(DSIZE*incr-1);
  783.     lastentry=rip->i_size/(DSIZE*incr)-1;
  784.     add=adir;
  785.     quit_trav=0;
  786.     traverse_dir(addfunc);
  787.     if(quit_trav)
  788.     {
  789.         /* If not last entry, restore size */
  790.         if(quit_trav==1) rip->i_size=tsize;
  791.         else cdirty=1;
  792.         quit_trav=0;
  793.         return 0;
  794.     }
  795.  
  796.     /* OK, need to add a zone, ignore any zone numbers already here,
  797.      * if there are any then they are bogus and should have been 
  798.      * removed in pass1.
  799.      */
  800.  
  801.     cdirty=1;
  802.     zoneadd=rip->i_size/BLOCKSIZE;
  803.  
  804.     if(!(addz=alloc_zone()))
  805.     {
  806.         printf("No free Zones\n");
  807.         return 1;
  808.     }
  809.     /* Room in direct zones ? */
  810.     if(zoneadd<NDIR) rip->i_zone[zoneadd]=addz;
  811.     else
  812.     /* Nope, need indirecton block */
  813.     {
  814.         zone_nr tmp[NINDIR];
  815.         zoneadd-=NDIR;
  816.         if(zoneadd >= NINDIR)
  817.         {
  818.             printf("Can't Expand Directory, Too Large\n");
  819.             clrbit(addz-minzone+1,szbitmap);
  820.             return 1;
  821.         }
  822.         if(!chk_range(rip->i_zone[NDIR]))
  823.         {
  824.             bzero((char *)tmp,BLOCKSIZE);
  825.             if( !(rip->i_zone[NDIR]=alloc_zone()) )        
  826.             {
  827.                 printf("No Free Zones\n");
  828.                 clrbit(addz-minzone+1,szbitmap);
  829.                 return 1;
  830.             }
  831.         }
  832.         else read_zone(rip->i_zone[NDIR],tmp);
  833.         tmp[zoneadd]=addz;
  834.         write_zone(rip->i_zone[NDIR],tmp);
  835.     }
  836.     cpdir(newzone,adir);
  837.  
  838.     write_zone(addz,newzone);
  839.     return 0;
  840. }
  841.  
  842. static int addfunc(dir,entry)
  843. dir_struct *dir;
  844. unsigned entry;
  845. {
  846.     if(entry<2) return 0;
  847.     /* If free , or last entry, overwrite */
  848.     if(!dir->d_inum || entry==lastentry)
  849.     {
  850.         cpdir(dir,add);
  851.         quit_trav=1;
  852.         if(entry==lastentry) quit_trav=2;
  853.         return 1;
  854.     }
  855.     return 0;
  856. }
  857.  
  858. static char *tname;
  859. static unsigned ifind;
  860.  
  861. static void show_name(inl)
  862. ilist *inl;
  863. {
  864.     inode_stat *itmp;
  865.  
  866.     char *tmpfnam;
  867.  
  868.     long pathlen;
  869.  
  870.     if(!(tname=malloc(incr*16-1)) ) fatal("Out of memory");
  871.  
  872.     /* Estimate maximum filename length of file
  873.      * do this by counting how many directories we pass
  874.      * through on way to root. Then assume all maximum
  875.      * length.
  876.      */
  877.  
  878.     for(pathlen=0,itmp=&inode_status[inl->iparent-1];;)
  879.     {
  880.         if(!(itmp->flag & I_FOUND)) break;
  881.         pathlen++;
  882.         if(itmp==inode_status) break;
  883.         itmp=&inode_status[itmp->parent-1];
  884.     }
  885.  
  886.     /* original link not counted so far and include \'s */
  887.  
  888.     pathlen = (pathlen+1)*incr*17-1;
  889.  
  890.     tmpfnam = malloc(pathlen);
  891.  
  892.     if(!tmpfnam) fatal("Out of Memory");
  893.  
  894.     strcpy(tmpfnam,inl->name);
  895.     strrev(tmpfnam);
  896.     strcat(tmpfnam,"\\");
  897.  
  898.     itmp=&inode_status[inl->iparent-1];
  899.     ifind=inl->iparent;
  900.  
  901.     while(ifind!=ROOT_INODE)
  902.     {
  903.         if(itmp->flag & I_FOUND)
  904.         {
  905.             lookup_name(itmp);
  906.             if(!*tname)
  907.             {
  908.                 fprintf(stderr,
  909.                     "Can't find name of inode %d\n",inl->inum);
  910.                 return;
  911.             }
  912.             strrev(tname);
  913.             strcat(tmpfnam,tname);
  914.             strcat(tmpfnam,"\\");
  915.         }
  916.         else
  917.         {
  918.             strcat(tmpfnam,"(nahpro)");
  919.             /* "orphan" backwards, geddit? */
  920.             break;
  921.         }        
  922.         ifind=itmp->parent;
  923.         itmp=&inode_status[itmp->parent-1];
  924.         
  925.     }
  926.  
  927.     strrev(tmpfnam);
  928.     fprintf(stderr,"Inode %5d Filename: %s\n",inl->inum,tmpfnam);
  929.  
  930.     free(tname);
  931.     free(tmpfnam);
  932. }
  933.  
  934. static void lookup_name(in)
  935. inode_stat *in;
  936. {
  937.     cino=in->parent;
  938.     tname[0]=0;
  939.     read_inode();
  940.     traverse_dir(i_to_name);
  941.     quit_trav=0;
  942. }    
  943.  
  944. static int i_to_name(dir,entry)
  945. dir_struct *dir;
  946. unsigned entry;
  947. {
  948.     if(entry < 2 ) return 0;    /* Ignore dots */
  949.     if(dir->d_inum==ifind) 
  950.     {
  951.         strncpy(tname,dir->d_name,incr*16-2);
  952.         tname[incr*16-2]=0;
  953.         quit_trav=1;
  954.     }
  955.     return 0;
  956. }
  957.  
  958. /* Make a 'lost+found' directory if none exists */
  959.  
  960. static int mklost()
  961. {
  962.     unsigned tino;
  963.     unsigned ctemp;
  964.     zone_nr tzone;
  965.     int i;
  966.     dir_struct dir[DPB];
  967.     printf("No lost+found directory\n");
  968.     if(!ask("Create?","Created")) return 0;
  969.     tino=alloc_inode();
  970.     if(!tino) return 0;
  971.     if(!(tzone=alloc_zone())) return 0;
  972.     ctemp=cino;
  973.     cino=tino;
  974.     read_inode();
  975.     for(i=1;i<NR_ZONE;i++) rip->i_zone[i]=0;
  976.     rip->i_zone[0]=tzone;
  977.     rip->i_mode=I_DIRECTORY | 0755;
  978.     rip->i_mtime=time(NULL);
  979.     rip->i_uid=0;
  980.     rip->i_gid=0;
  981.     rip->i_size=DSIZE*2*incr;
  982.     rip->i_nlinks=2;
  983.     cdirty=1;
  984.     strcpy(dir[0].d_name,".");
  985.     dir[0].d_inum=tino;
  986.     strcpy(dir[incr].d_name,"..");
  987.     dir[incr].d_inum=ROOT_INODE;
  988.     write_zone(tzone,dir);
  989.  
  990.     strcpy(dir[0].d_name,lfname);
  991.     dir[0].d_inum=tino;
  992.  
  993.     cino=ROOT_INODE;
  994.     read_inode();
  995.     rip->i_nlinks++;
  996.     cdirty=1;
  997.  
  998.     add_dirent(dir);
  999.  
  1000.     cino=ctemp;
  1001.     lfinode=tino;
  1002.  
  1003.     inode_status[tino-1].flag = I_DIR|I_D|I_DD|I_FOUND;
  1004.     inode_status[tino-1].links=0;
  1005.     inode_status[tino-1].parent=ROOT_INODE;
  1006.  
  1007.     return 1;
  1008. }
  1009.  
  1010. /* Simple enoungh this one : check '.' and '..' are present, check '.' points
  1011.  * to this directory, note the value of '..' . Make elementary fixes as well.
  1012.  */
  1013.  
  1014. static void check_dots()
  1015. {
  1016.     dir_struct dir[DPB];
  1017.     int dirty=0;
  1018.     if(chk_range(rip->i_zone[0]))
  1019.     {
  1020.         read_zone(rip->i_zone[0],dir);
  1021.         if(strcmp(dir->d_name,"."))
  1022.         {
  1023.             printf("No '.' in directory inode %ld\n",cino);
  1024.             if(ask("Fix?","Fixed"))
  1025.             {
  1026.             /* If this entry is occupied, add an identical entry
  1027.              * to the dir, because this one will be overwritten.
  1028.              */
  1029.             if(chk_irange(dir->d_inum)) add_dirent(dir);
  1030.  
  1031.             strcpy(dir[0].d_name,".");
  1032.             dir->d_inum=cino;
  1033.             dirty=1;
  1034.             ist->flag|=I_D;
  1035.             }
  1036.         }
  1037.         else ist->flag|=I_D;
  1038.  
  1039.         if(dir->d_inum!=cino)
  1040.         {
  1041.             printf("Bad '.' Entry in directory inode %ld\n",cino);
  1042.             if(ask("Fix?","Fixed"))
  1043.             {
  1044.                 dir->d_inum=cino;
  1045.                 dirty=1;
  1046.             }
  1047.         }
  1048.  
  1049.         if(strcmp(dir[incr].d_name,".."))
  1050.         {
  1051.             printf("Missing '..' in directory inode %ld",cino);
  1052.             if(ask("Fix?","Fixed"))
  1053.             {
  1054.                 if(chk_irange(dir[incr].d_inum)) 
  1055.                             add_dirent(&dir[incr]);
  1056.  
  1057.                 strcpy(dir[incr].d_name,"..");
  1058.                 dir[incr].d_inum=0;    /* Can't fix this yet */
  1059.                 ist->flag|=I_FDD;
  1060.                 ist->flag|=I_DD;
  1061.                 dirty=1;
  1062.             }
  1063.         }
  1064.         else
  1065.         {
  1066.             ist->parent=dir[incr].d_inum;
  1067.             ist->flag|=I_DD;
  1068.         }
  1069.         if(dirty) write_zone(rip->i_zone[0],dir);
  1070.     }
  1071. }
  1072.  
  1073. /* Check inode numbers against list after checking _pass2 wont kill the entry */
  1074.  
  1075. static int pass2(dir,entry)
  1076. dir_struct *dir;
  1077. unsigned entry;
  1078. {
  1079.     int ret;
  1080.     ret=_pass2(dir,entry);
  1081.  
  1082.     if(!ret)
  1083.     {
  1084.         llist *p;
  1085.         for(p=inums;p;p=p->next) if(dir->d_inum==p->member) break;
  1086.         if(p)
  1087.         {
  1088.             ilist *nxt;
  1089.             nxt=malloc(sizeof(ilist)+incr*16);
  1090.             if(!nxt) fatal("Out of memory");
  1091.             strncpy(nxt->name,dir->d_name,incr*16-2);
  1092.             nxt->name[incr*16-2]=0;
  1093.             nxt->inum=dir->d_inum;
  1094.             nxt->iparent=cino;
  1095.             nxt->next=inolist;
  1096.             inolist=nxt;
  1097.         }
  1098.     }
  1099.  
  1100.     return ret;
  1101. }
  1102.  
  1103. /* OK this is the nasty bit. At this point we know the value of '..' in a
  1104.  * directory (if present). Check all directory entries and offer fixes, also
  1105.  * mark each inode as it is 'found' and update link counts.
  1106.  */
  1107.  
  1108. static int _pass2(dir,entry)
  1109. dir_struct *dir;
  1110. unsigned entry;
  1111. {
  1112.     inode_stat *iarr;
  1113.  
  1114.     if(!dir->d_inum) return 0;
  1115.  
  1116.     if(!chk_irange(dir->d_inum))
  1117.     {
  1118.         inerr("Ilegal Inode Number\n");
  1119.         if(ask("Delete?","Deleted"))
  1120.         {
  1121.             dir->d_inum=0;
  1122.             return 1;
  1123.         }
  1124.         return 0;    /* Can't do anything else with it */
  1125.     }
  1126.  
  1127.     if( (cino==ROOT_INODE) && !strcmp(dir->d_name,lfname))lfinode=dir->d_inum;
  1128.  
  1129.     iarr=&inode_status[dir->d_inum-1];
  1130.     iarr->links--;
  1131.  
  1132.     if(badname(dir->d_name))
  1133.     {
  1134.         printf("Bad Name %.*s in Directory Inode %ld\n",
  1135.                     MMAX_FNAME(incr),dir->d_name,cino);
  1136.         if(ask("Delete?","Deleted"))
  1137.         {
  1138.             dir->d_inum=0;
  1139.             iarr->links++;
  1140.             return 1;
  1141.         }
  1142.     }
  1143.  
  1144.     if(entry && (!strcmp(dir->d_name,".")))
  1145.     {
  1146.         inerr("Extra '.' entry");
  1147.         if(ask("Delete?","Deleted"))
  1148.         {
  1149.             dir->d_inum=0;
  1150.             iarr->links++;
  1151.             return 1;
  1152.         }
  1153.         return 0;
  1154.     }
  1155.  
  1156.     if( (entry!=1) && !strcmp(dir->d_name,"..") )
  1157.     {
  1158.         inerr("Extra '..' entry");
  1159.         if(ask("Delete?","Deleted"))
  1160.         {
  1161.             dir->d_inum=0;
  1162.             iarr->links++;
  1163.             return 1;
  1164.         }
  1165.         return 0;
  1166.     }
  1167.  
  1168.     if( ( (entry==0) && (ist->flag & I_D) )
  1169.                 || ( (entry==1) && (ist->flag & I_DD ) ) )
  1170.             return 0;
  1171.  
  1172.     if(iarr->flag & I_FREE)
  1173.     {
  1174.         inerr("Bad Link To Free Inode");
  1175.         if(ask("Delete?","Deleted"))
  1176.         {
  1177.             dir->d_inum=0;
  1178.             iarr->links++;
  1179.             return 1;
  1180.         }
  1181.         return 0;
  1182.     }
  1183.  
  1184.     /* Tricky bit : link to directory. For this pass only recognise as
  1185.      * 'found' if the link is present in the correct parent directory.
  1186.      * If this isn't the case either '..' is wrong or this is an illegal
  1187.      * hard link, this is resolved on the next pass.
  1188.      * If it isn't a directory then mark found, as multiple links are OK.
  1189.      */
  1190.     if(iarr->flag & I_DIR)
  1191.     {
  1192.         if (iarr->parent==cino)
  1193.         {
  1194.     /* If the 'FOUND' flag is set then multiple links in this dir */
  1195.             if(iarr->flag & I_FOUND)
  1196.             {
  1197.                 inerr("Illegal Hard Link To Directory");
  1198.                 if(ask("Remove","Removed"))
  1199.                 {
  1200.                     dir->d_inum=0;
  1201.                     iarr->links++;
  1202.                     return 1;
  1203.                 }
  1204.             }
  1205.             else iarr->flag |= I_FOUND;
  1206.         }
  1207.         else ist->flag |= I_LINK;
  1208.     }
  1209.     else iarr->flag |= I_FOUND;
  1210.  
  1211.     return 0;
  1212. }
  1213.  
  1214. /* At this point all directories which have a link in '..' have the flag
  1215.  * I_FOUND. So if a hard link to a directory is found then it is one of:
  1216.  * 1. An erroneous hard link (if it isn't in the parent and I_FOUND set).
  1217.  * 2. A proper link but the value of '..' is wrong in the linked dir.
  1218.  * If '..' is wrong and two hard links are found then the first is taken to
  1219.  * be valid, there isn't any real way to find out the genuine link in this
  1220.  * case.
  1221.  */
  1222.  
  1223. static int pass2a(dir,entry)
  1224. dir_struct *dir;
  1225. unsigned entry;
  1226. {
  1227.     inode_stat *iarr;
  1228.     /* Ignore dot's and invalid links */
  1229.     if( (!entry && (ist->flag & I_D) )||
  1230.         (entry==1 && (ist->flag & I_DD) ) ||
  1231.         !chk_irange(dir->d_inum) ) return 0;    
  1232.     iarr=&inode_status[dir->d_inum-1];
  1233.     /* If not dir , ignore */
  1234.  
  1235.     if(! (iarr->flag & I_DIR) ) return 0;
  1236.  
  1237.     /* Is this the parent ? */
  1238.     if(iarr->parent==cino) return 0;
  1239.  
  1240.     /* Does parent have a valid link ? */
  1241.     if(iarr->flag & I_FOUND)
  1242.     {
  1243.         printf("Bad Hard Link to Directory in Inode %ld\n",cino);
  1244.         if(ask("Remove?","Removed"))
  1245.         {
  1246.             dir->d_inum=0;
  1247.             iarr->links++;
  1248.             return 1;
  1249.         }
  1250.         return 0;
  1251.     }
  1252.  
  1253.     /* Hmm '..' parent has no link, must be invalid '..' */
  1254.  
  1255.     iarr->flag|=I_FOUND;
  1256.     iarr->flag|=I_FIXDD;
  1257.     iarr->parent=cino;
  1258.     return 0;
  1259. }
  1260.  
  1261. /* Almost there: fix any directories '..' entries if there is an
  1262.  * error found, if the I_FDD flag is set, do the changes silently.
  1263.  */
  1264.  
  1265. static void fix_dots()
  1266. {
  1267.     dir_struct dir[DPB];
  1268.     if(!(ist->flag & I_FDD)) 
  1269.     {
  1270.         inerr("Bad '..' entry");
  1271.         if(!ask("Fix?","Fixed")) return;
  1272.     }
  1273.     read_zone(rip->i_zone[0],dir);
  1274.     if(chk_irange(dir[incr].d_inum))
  1275.                 inode_status[dir[incr].d_inum-1].links++;
  1276.     dir[incr].d_inum=ist->parent;
  1277.     inode_status[ist->parent-1].links--;
  1278.     write_zone(rip->i_zone[0],dir);
  1279. }
  1280.  
  1281. /* Inode readers : there are two of these. next_inode() is used in the
  1282.  * initial stages where all inodes have to be read twice, it uses a big
  1283.  * buffer for this purpose, if the 'cdirty' flag is set then it writes out
  1284.  * the buffer first.
  1285.  */
  1286.  
  1287. static d_inode *ncache_start,*ncache_end,*ncache;
  1288. static long ncache_blk;
  1289.  
  1290. /* Initialise and flush big cache */
  1291. static void next_init()
  1292. {
  1293.     if(!ncache_start)
  1294.     {
  1295.         ncache_start=malloc(NSIZE*BLOCKSIZE);
  1296.         if(!ncache_start)fatal("No memory for inode cache");
  1297.         ncache_end=ncache_start+NSIZE*IPB;
  1298.     }
  1299.     if(cdirty) write_blocks(ncache_blk,NSIZE,ncache_start);
  1300.     cdirty=0;
  1301.     ncache=ncache_start;
  1302.     ncache_blk=0;
  1303. }
  1304.  
  1305. static void next_inode()
  1306. {
  1307.     if(ncache_blk==0)
  1308.     {
  1309.         read_blocks(ioff,NSIZE,ncache_start);
  1310.         ncache_blk=ioff;
  1311.     }
  1312.     if(ncache!=ncache_end)
  1313.     {
  1314.         rip=ncache;
  1315.         ncache++;
  1316.         return;
  1317.     }
  1318.     if(cdirty)
  1319.     {
  1320.         cdirty=0;
  1321.         write_blocks(ncache_blk,NSIZE,ncache_start);
  1322.     }
  1323.     ncache_blk+=NSIZE;
  1324.     read_blocks(ncache_blk,NSIZE,ncache_start);
  1325.     ncache=ncache_start;
  1326.     rip=ncache;
  1327.     ncache++;
  1328.     return;
  1329. }
  1330.  
  1331. static d_inode ltmp[IPB];
  1332.  
  1333. static void read_inode_init()
  1334. {
  1335.     if(cdirty)
  1336.     {
  1337.         write_blocks(ncache_blk,1,ltmp);
  1338.         cdirty=0;
  1339.     }
  1340.     ncache_blk=0;
  1341. }
  1342.  
  1343. static void read_inode()
  1344. {
  1345.     zone_nr blk=ioff+(cino-1)/IPB  ;
  1346.     if(!cino || (cino>maxino) )fatal("Internal error: inode out of range");
  1347.     if(ncache_blk!=blk)
  1348.     {
  1349.         if(cdirty)
  1350.         {
  1351.             cdirty=0;
  1352.             write_blocks(ncache_blk,1,ltmp);
  1353.         }
  1354.         ncache_blk=blk;
  1355.         read_blocks(ncache_blk,1,ltmp);
  1356.     }
  1357.     rip=<mp[(cino-1)%IPB];
  1358. }
  1359.  
  1360. static long alloc_inode()
  1361. {
  1362.     long ret;
  1363.     inode_stat *istmp=inode_status;
  1364.     for(ret=0;ret<maxino;ret++,istmp++)if(istmp->flag &I_FREE) return ret+1;
  1365.     return 0;
  1366. }
  1367.  
  1368. /* Reallocate root inode. Here the root inode is set up as a dir with '.','..'
  1369.  * and 'lost+found'. The connectivity algorithm should then be able to reconnect
  1370.  * all the orphaned inodes. Note: at this point the inode structures should at
  1371.  * least be set up, and the shadow zone bitmap, so we can safely allocate new
  1372.  * zones/inodes.
  1373.  */
  1374.  
  1375. static void fix_root()
  1376. {
  1377.     long z1,z2;
  1378.     time_t now;
  1379.  
  1380.     dir_struct rdir[DPB];
  1381.  
  1382.     cino=ROOT_INODE;
  1383.     /* First things first : allocate 2 zones */
  1384.     z1=alloc_zone();
  1385.  
  1386.     z2=alloc_zone();
  1387.  
  1388.     if(!z1 || !z2) 
  1389.         fatal("No Free Zones To Reallocate Root Inode");
  1390.  
  1391.     lfinode=alloc_inode();
  1392.  
  1393.     if(!lfinode)
  1394.         fatal("No Free Inodes To Reallocate 'lost+found'");
  1395.  
  1396.     /* Setup inode status flags */
  1397.     inode_status->flag= I_DIR | I_FOUND;
  1398.     inode_status->links=3;
  1399.     inode_status[lfinode-1].flag= I_DIR;
  1400.     inode_status[lfinode-1].links=2;
  1401.  
  1402.     read_inode_init();
  1403.     read_inode();
  1404.  
  1405.     now=time((time_t *)NULL);
  1406.  
  1407.     *rip=zinode;
  1408.  
  1409.     /* Setup root inode */
  1410.     rip->i_size= DSIZE*incr*3;        /* 3 entries */
  1411.     rip->i_mode= I_DIRECTORY | 0777;    /* Dir + 777 mode */
  1412.     rip->i_zone[0]=z1;            /* 1 Zone */
  1413.     rip->i_mtime=now;
  1414.     rip->i_nlinks=3;
  1415. #ifdef V2
  1416.     rip->i_atime=now;
  1417.     rip->i_ctime=now;
  1418. #endif
  1419.  
  1420.     /* Root Directory */
  1421.     bzero(rdir,BLOCKSIZE);
  1422.             
  1423.     strcpy(rdir[0].d_name,".");
  1424.     rdir[0].d_inum=ROOT_INODE;
  1425.     strcpy(rdir[incr].d_name,"..");
  1426.     rdir[incr].d_inum=ROOT_INODE;
  1427.     strcpy(rdir[incr*2].d_name,lfname);
  1428.     rdir[incr*2].d_inum=lfinode;
  1429.  
  1430.     write_zone(z1,rdir);
  1431.     cdirty=1;
  1432.  
  1433.     cino=lfinode;
  1434.     read_inode();
  1435.  
  1436.     /* Setup 'lost+found' inode */
  1437.     
  1438.     *rip=zinode;
  1439.  
  1440.     rip->i_size=DSIZE*incr*2;
  1441.     rip->i_mode=I_DIRECTORY | 0777;
  1442.     rip->i_zone[0]=z2;
  1443.     rip->i_mtime=now;
  1444.     rip->i_nlinks=2;
  1445. #ifdef V2
  1446.     rip->i_atime=now;
  1447.     rip->i_ctime=now;
  1448. #endif
  1449.  
  1450.     /* l+f dir same as root except for '.' */
  1451.     rdir[0].d_inum=lfinode;
  1452.  
  1453.     write_zone(z2,rdir);
  1454.     cdirty=1;
  1455.  
  1456.     read_inode_init();
  1457. }
  1458.